package cn.ltgodm.template.user.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.ltgodm.template.common.annotation.DataScope;
import cn.ltgodm.template.common.constant.Constants;
import cn.ltgodm.template.common.constant.UserConstants;
import cn.ltgodm.template.common.domain.vo.RoleVO;
import cn.ltgodm.template.common.domain.vo.UserVO;
import cn.ltgodm.template.common.exception.ServiceException;
import cn.ltgodm.template.common.utils.SecurityUtils;
import cn.ltgodm.template.common.utils.SpringUtils;
import cn.ltgodm.template.common.utils.StringUtils;
import cn.ltgodm.template.user.domain.entity.RoleMenu;
import cn.ltgodm.template.user.domain.param.RoleParam;
import cn.ltgodm.template.user.domain.param.RoleQueryParam;
import cn.ltgodm.template.user.service.RoleDeptService;
import cn.ltgodm.template.user.service.RoleMenuService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import cn.ltgodm.template.common.domain.entity.Role;
import cn.ltgodm.template.user.service.RoleService;
import cn.ltgodm.template.user.mapper.RoleMapper;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import java.util.*;

/**
 * @author wenpeng
 * @description 针对表【lt_role(角色信息表)】的数据库操作Service实现
 * @date 2024-03-17 22:12:11
 */
@Service
public class RoleServiceImpl extends ServiceImpl<RoleMapper, Role> implements RoleService {

    @Resource
    private RoleMapper roleMapper;
    @Resource
    private RoleMenuService roleMenuService;
    @Resource
    private RoleDeptService roleDeptService;


    /**
     * 获取用户角色列表
     *
     * @param userId 用户id
     * @return 返回角色集合
     */
    @Override
    public Set<String> selectRolePermissionByUserId(Long userId) {
        List<RoleVO> roleVOList = roleMapper.selectRolePermissionByUserId(userId);
        Set<String> hashSet = new HashSet<>();
        for (RoleVO roleVO : roleVOList) {
            if (ObjectUtil.isNotNull(roleVO)) {
                hashSet.addAll(Arrays.asList(roleVO.getRoleKey().trim().split(",")));
            }
        }
        return hashSet;
    }

    @Override
    public List<RoleVO> selectRoleAll() {
        RoleQueryParam roleQueryParam = new RoleQueryParam();
        roleQueryParam.setPageSize(-1);
        IPage<RoleVO> rolePage = SpringUtils.getAopProxy(this).selectRoleList(roleQueryParam);
        return rolePage.getRecords();
    }

    /**
     * 分页查询角色信息
     *
     * @param roleQueryParam 查询参数
     * @return 返回分页信息
     */
    @Override
    @DataScope(deptAlias = "d")
    public IPage<RoleVO> selectRoleList(RoleQueryParam roleQueryParam) {
        LambdaQueryWrapper<Role> lqw = getQueryWrapper(roleQueryParam);
        IPage<RoleVO> page = new Page<>(roleQueryParam.getPageNum(), roleQueryParam.getPageSize());
        lqw.eq(Role::getDelFlag, Constants.DEL_FLAG_NORMAL);
        return roleMapper.selectRoleList(page, lqw, roleQueryParam.getParams());
    }

    /**
     * 校验角色名称是否唯一
     *
     * @param queryParam 查询参数
     * @return 返回是否唯一
     */
    @Override
    public boolean checkRoleNameUnique(RoleParam queryParam) {
        Long roleId = ObjectUtil.isNull(queryParam.getRoleId()) ? -1L : queryParam.getRoleId();
        Role role = roleMapper.checkRoleNameUnique(queryParam.getRoleName());
        if (ObjectUtil.isNotNull(role) && role.getRoleId().compareTo(roleId) != 0) {
            return UserConstants.NOT_UNIQUE;
        }
        return UserConstants.UNIQUE;
    }

    /**
     * 校验角色权限是否唯一
     *
     * @param queryParam 查询参数
     * @return 返回是否唯一
     */
    @Override
    public boolean checkRoleKeyUnique(RoleParam queryParam) {
        Long roleId = ObjectUtil.isNull(queryParam.getRoleId()) ? -1L : queryParam.getRoleId();
        Role role = roleMapper.checkRoleKeyUnique(queryParam.getRoleKey());
        if (ObjectUtil.isNotNull(role) && role.getRoleId().compareTo(roleId) != 0) {
            return UserConstants.NOT_UNIQUE;
        }
        return UserConstants.UNIQUE;
    }

    /**
     * 新增角色
     *
     * @param roleParam 新增用户信息
     * @return 返回影响行数
     */
    @Override
    @Transactional
    public int insertRole(RoleParam roleParam) {
        Role role = new Role();
        BeanUtils.copyProperties(roleParam, role);
        role.setCreateBy(SecurityUtils.getLoginUser().getUsername());
        int row = roleMapper.insert(role);
        roleParam.setRoleId(role.getRoleId());
        insertRomeMenu(roleParam);
        return row;
    }

    /**
     * 修改角色信息
     * @param RoleParam 角色信息
     * @return 返回影响行数
     */
    @Override
    @Transactional
    public int updateRole(RoleParam RoleParam) {
        RoleParam.setUpdateBy(SecurityUtils.getLoginUser().getUsername());
        int row = roleMapper.updateById(RoleParam);
        //删除角色对应权限
        roleMenuService.removeRoleMenuByRoleId(RoleParam.getRoleId());
        //新增角色权限信息
        insertRomeMenu(RoleParam);
        return row;
    }

    /**
     * 删除角色信息
     * @param roleIds 角色id
     * @return 返回影响行数
     */
    @Override
    @Transactional
    public int deleteRoleByIds(Long[] roleIds) {
        for (Long roleId : roleIds) {
            Role role = new Role();
            role.setRoleId(roleId);
            checkRoleAllowed(role);
            checkRoleDataScope(roleId);
            RoleVO roleVO = roleMapper.selectRoleById(roleId);
            if (ObjectUtil.isNotNull(roleVO)) {
                throw new ServiceException(StrUtil.format("角色{}已分配，不能删除", roleVO.getRoleName()));
            }
        }
        //删除关联角色菜单
        roleMenuService.removeRoleMenu(roleIds);
        //删除角色与部门关联
        roleDeptService.removeRoleDept(roleIds);
        //删除角色信息
        LambdaQueryWrapper<Role> lqw = new LambdaQueryWrapper<>();
        lqw.in(Role::getRoleId, Arrays.asList(roleIds));
        return roleMapper.delete(lqw);
    }

    /**
     * 根据角色id获取角色信息
     * @param roleId 角色id
     * @return 返回角色信息
     */
    @Override
    public RoleVO selectRoleById(Long roleId) {
        return roleMapper.selectRoleById(roleId);
    }

    /**
     * 修改角色状态
     * @param roleParam 角色信息
     * @return 返回影响行数
     */
    @Override
    public int updateRoleStatus(RoleParam roleParam) {
        checkRoleAllowed(roleParam);
        checkRoleDataScope(roleParam.getRoleId());
        checkRoleDataScope(roleParam.getRoleId());
        Role role = new Role();
        role.setRoleId(roleParam.getRoleId());
        role.setStatus(roleParam.getStatus());
        role.setUpdateBy(SecurityUtils.getLoginUser().getUsername());
        return roleMapper.updateById(role);
    }

    /**
     * 校验角色是否有数据权限
     * @param roleId 角色id
     */
    private void checkRoleDataScope(Long roleId) {
        if(!UserVO.isAdmin(SecurityUtils.getUserId())){
            RoleQueryParam roleQueryParam = new RoleQueryParam();
            roleQueryParam.setRoleId(roleId);
            IPage<RoleVO> roleVOIPage = SpringUtils.getAopProxy(this).selectRoleList(roleQueryParam);
            if (ObjectUtil.isNull(roleVOIPage) || CollectionUtil.isEmpty(roleVOIPage.getRecords())){
                throw new ServiceException("没有权限访问角色数据！");
            }
        }
    }

    /**
     * 校验角色是否允许操作
     * @param role 角色
     */
    private void checkRoleAllowed(Role role) {
        if (ObjectUtil.isNotEmpty(role) && RoleVO.isAdmin(role.getRoleId())){
            throw new ServiceException("不允许操作超级管理员角色");
        }
    }

    /**
     * 新增角色权限信息
     *
     * @param roleParam 角色信息
     */
    private void insertRomeMenu(RoleParam roleParam) {
        List<RoleMenu> roleMenuList = new ArrayList<>();
        for (Long menuId : roleParam.getMenuIds()) {
            RoleMenu roleMenu = new RoleMenu();
            roleMenu.setRoleId(roleParam.getRoleId());
            roleMenu.setMenuId(menuId);
            roleMenuList.add(roleMenu);
        }
        if (CollectionUtil.isNotEmpty(roleMenuList)) {
            roleMenuService.saveBatch(roleMenuList);
        }
    }

    /**
     * 构造查询参数
     *
     * @param roleQueryParam 查询参数
     * @return 查询构造器
     */
    private LambdaQueryWrapper<Role> getQueryWrapper(RoleQueryParam roleQueryParam) {
        LambdaQueryWrapper<Role> lqw = new LambdaQueryWrapper<>();
        lqw
                .eq(ObjectUtil.isNotEmpty(roleQueryParam.getRoleId()), Role::getRoleId, roleQueryParam.getRoleId())
                .eq(StringUtils.isNotEmpty(roleQueryParam.getRoleName()), Role::getRoleName, roleQueryParam.getRoleName())
                .eq(StringUtils.isNotEmpty(roleQueryParam.getStatus()), Role::getStatus, roleQueryParam.getStatus());
        lqw.orderByAsc(Role::getRoleSort);
        return lqw;
    }

}